#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QLocale>
#include <QXmlQuery>

#include "defines.h"

#include "configxmlparser.h"
#include "directoryutilities.h"
#include "filecopier.h"
#include "fileutilities.h"
#include "infoplistparser.h"
#include "settings.h"

#include "maemo5defines.h"
#include "maemo5processrunner.h"
#include "maemo5qtprojectgenerator.h"
#include "maemo5settingsgui.h"
#include "maemo5statusupdater.h"



Maemo5QtProjectGenerator::Maemo5QtProjectGenerator(GeneratorOutputView & outputView,
                                                   QObject             * parent)
    : m_outputView(outputView),
      m_processRunner(NULL),
      m_currentGeneratorPhase(M5_INITIAL),
      m_generatorTarget(NO_TARGET),
      m_resolvedWidgetType(UNKNOWN_WIDGET)
{
    m_processRunner = new Maemo5ProcessRunner(*this);

    // TODO should come from some defines
    m_ignorePatterns.insert("*.png");
}


Maemo5QtProjectGenerator::~Maemo5QtProjectGenerator()
{
    delete m_processRunner;
    m_processRunner = 0;
}


IStatusUpdater * Maemo5QtProjectGenerator::createStatusUpdater(QObject * parent)
{
    IStatusUpdater
        * rv = new Maemo5StatusUpdater(*this,
                                       parent);

    return rv;
}

const PlatformType& Maemo5QtProjectGenerator::platform()
{
    m_platform.m_platformName = MAEMO5_PLATFORMNAME;
    m_platform.m_platformVersion = 5;
    m_platform.m_qtVersion = Settings::get(Settings::QtVersion).toInt();

    return m_platform;
}

void Maemo5QtProjectGenerator::build(const QString & widgetFile,
                                     RcSession     & /* rcSession */)
{
    emit started(BUILD);
    m_generatorTarget = BUILD;
    m_currentGeneratorPhase = M5_INITIAL;
    m_resolvedWidgetType = UNKNOWN_WIDGET;
    if (!registerStatus(prepareEnvironment(widgetFile)))
            return;

    updateSubstitutions(widgetFile);
    copyWidgetDirectory(widgetFile);
}


void Maemo5QtProjectGenerator::rebuild(RcSession     & /* rcSession */)
{
    emit started(REBUILD);
    m_generatorTarget = REBUILD;
    m_currentGeneratorPhase = M5_INITIAL;
    startBuild();
}


void Maemo5QtProjectGenerator::preview(const QString &widgetFile)
{
    // TODO this method will be removed from IQtProjectGenerator interface
    ;
}


void Maemo5QtProjectGenerator::closeProject()
{
    m_generatorTarget = NO_TARGET;
    m_currentGeneratorPhase = M5_INITIAL;
    m_resolvedWidgetType = UNKNOWN_WIDGET;
}


GeneratorOutputView & Maemo5QtProjectGenerator::outputView() const
{
    return m_outputView;
}


GeneratorData & Maemo5QtProjectGenerator::generatorData()
{
    return m_generatorData;
}


GeneratorPhase Maemo5QtProjectGenerator::getCurrentPhase() const
{
    return m_currentGeneratorPhase;
}


GeneratorTarget Maemo5QtProjectGenerator::getTarget() const
{
    return m_generatorTarget;
}


QString Maemo5QtProjectGenerator::getStatusText() const
{
    QString statusText;

    switch(m_currentGeneratorPhase.m_phase)
    {
    case M5_UNZIP_WIDGET:
        statusText = HAG_STATUS_EXTRACTING_WIDGET;
        break;
    case M5_DPKG_BUILDPACKAGE:
        statusText = QString("Running 'mad dpkg-buildpackage'");
        break;
    case M5_INITIAL:
        statusText = HAG_STATUS_IDLE;
        break;
    case M5_ENDED_SUCCESSFULLY:
        statusText = HAG_STATUS_COMPLETED_OK;
        break;
    case M5_ENDED_WITH_ERRORS:
        statusText = HAG_STATUS_COMPLETED_NOTOK;
        break;
    }

    return statusText;
}


QWidget * Maemo5QtProjectGenerator::createSettingsWidget(const QString & widgetFile,
                                                         QWidget       * parent) const
{
    const QString
        TODO_COPYRIGHT_DIR("/templates/copyright/");

    QString
        copyrightDirPath = QApplication::applicationDirPath() + TODO_COPYRIGHT_DIR;

    QDir
        copyRightDir(copyrightDirPath);
    QList<QString>
        licenses = copyRightDir.entryList(QDir::Dirs
                                          | QDir::NoDotAndDotDot);

    // OBS (const_cast<Maemo5QtProjectGenerator*>(this))->sniffAppNames(widgetFile);
    QPair<QString, QString>
        appNames = FileUtilities::sniffAppNames(widgetFile);

    QWidget
        * rv = new Maemo5SettingsGui(licenses,
                                     // OBS m_appName,
                                     appNames.first,
                                     parent);

    return rv;
}


void Maemo5QtProjectGenerator::saveSettings(QWidget * settingsWidget) const
{
    Maemo5SettingsGui
        * maemo5SettingsGui = dynamic_cast<Maemo5SettingsGui*>(settingsWidget);

    if (maemo5SettingsGui != NULL)
    {
        maemo5SettingsGui->saveSettings();
    }
}


QStringList Maemo5QtProjectGenerator::errorsForTarget(GeneratorTarget generatorTarget) const
{
    QStringList
        rv;

    QString
        bashPath = Maemo5SettingsGui::bashPath();

    if (bashPath.length() == 0)
    {
        rv.append("Path to bash.exe is not set");
    }
    else if (!QFileInfo(bashPath).isFile())
    {
        rv.append("Path to bash.exe is set, but is invalid");
    }

    QFile log(Settings::get(Settings::LogFilePath).toString());
    if (!log.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        // Failed to open the log file
        if (generatorTarget != NO_TARGET)
        {
            rv.append("Failed to open log file for writing! Check settings.");
        }
    }
    log.close();

    if (Settings::get(Settings::HybridAuthor).toString().length() == 0)
    {
        rv.append("Author is not set");
    }

    if (Settings::get(Settings::HybridEmail).toString().length() == 0)
    {
        rv.append("Author email is not set");
    }
    else
    {
        QRegExp
            validEmailRx("(\\w|\\.-)+@(\\w|\\.)+");
        if (validEmailRx.indexIn(Settings::get(Settings::HybridEmail).toString()) == -1)
        {
            rv.append("Author email is set, but seems broken");
        }
    }

    // TODO - check long and short descriptions too

    return rv;
}


IQtProjectGenerator::PkgInstallResult
Maemo5QtProjectGenerator::installPkg(const QFileInfo & pkgFile) const
{
    return PKGINSTALL_NOT_SUPPORTED;
}


void Maemo5QtProjectGenerator::dpkgBuildPackageFinished(int exitCode,
                                                        QProcess::ExitStatus exitStatus)
{
    if (!exitCode && !exitStatus)
    {
        m_currentGeneratorPhase = M5_ENDED_SUCCESSFULLY;
        emit finished(EXIT_SUCCESS);
    }
    else
    {
        registerStatus(false);

        QString msg = QString(ERR_PROCESS_FINISHED_WITH_ERRORS_CANNOT_CONTINUE).arg("mad dpkg-buildpackage")
                      + QString(MSG_PROCESS_EXIT_CODE_STATUS).arg(exitCode).arg(exitStatus);
        m_outputView.printOutput(msg);
        emit finished(EXIT_FAILURE);
    }
}


void Maemo5QtProjectGenerator::widgetFilesCopied(int exitCode,
                                                 QProcess::ExitStatus exitStatus)
{
    if (!exitCode && !exitStatus)
    {
        prepareProject();
    }
    else
    {
        registerStatus(false);
        QString msg = QString(ERR_PROCESS_FINISHED_WITH_ERRORS_CANNOT_CONTINUE).arg(UNZIP_APP_NAME) + QString(MSG_PROCESS_EXIT_CODE_STATUS).arg(exitCode).arg(exitStatus);
        m_outputView.printOutput(msg);
        emit finished(EXIT_FAILURE);
    }
}


void Maemo5QtProjectGenerator::copyWidgetDirectory(const QString &filename)
{
    QFileInfo targetInfo(filename);
    if (!targetInfo.isDir())
    {
        // Not a directory, so proceed with unzip instead
        unzipWidgetFile(filename);
    }
    else
    {
        // Directory -- copy files directly
        qDebug() << "Copy directory";
        m_resolvedWidgetType = DIRECTORY;
        DirectoryUtilities dirUtil(m_outputView, m_generatorData);
        QString dest = m_generatorData.widgetDirectory();
        if (dirUtil.copyDirectory(filename, dest))
                widgetFilesCopied(0);
        else
                return;
    }
}


bool Maemo5QtProjectGenerator::prepareProject()
{
    // copy framework and plugin source files to the build directory
    if (!registerStatus(copyFrameworkAndPluginSrcFiles()))
        return false;

    // find out type of widget package
    sniffWidgetType();
    if (!registerStatus(m_resolvedWidgetType != UNKNOWN_WIDGET))
    {
        return false;
    }

    if (m_resolvedWidgetType != WRT_WIDGET)
    {
        // create info.plist and copy widget files to right place
        if (!registerStatus(prepareEnvironmentForNonWRTWidget()))
            return false;
    }

    // read in info.plist
    if (!registerStatus(handleWidgetConfigFile()))
        return false;

    if (!registerStatus(copyHybridApiJs()))
        return false;

    if (!Settings::get(Settings::TextSelectionEnabled).toBool())
    {
        if (!registerStatus(copyDisableSelectionCSS()))
        {
            return false;
        }
    }

    // copy all maemo5 build related files, except the copyright
    if (!registerStatus(copyMaemo5Files()))
        return false;

    // copy the copyright file
    if (!registerStatus(copyCopyrightFile()))
        return false;

    // read in info of widget directory
    handleWidgetDirectory();

    // update main.cpp file
    if (!registerStatus(updateMainFile()))
        return false;

    // update mainwindow.cpp file
    if (!registerStatus(updateMainWindowFile()))
        return false;

    // generate Qt resource file
    parseWidgetResourceFile();

    // Update the framework project file
    if (!registerStatus(updateFrameworkProjectFile()))
        return false;

    /* TODO LATER - mobility plugins are ignored in the first version
    // Create mw.pro file that ties the plugins to the project,
    // also updates the plugin project files to e.g. include correct
    // Qt Mobility paths.
    if (!registerStatus(parsePluginsProjectFile()))
        return false;
    */

    startBuild();

    return true;
}


bool Maemo5QtProjectGenerator::prepareEnvironment(const QString &widgetFile)
{
    // clear data structures
    m_generatorData.clearAll();
    m_generatorData.initPaths(widgetFile,
                              MAEMO5_PLATFORMNAME);

    QString basePath = m_generatorData.basePath();
    QString buildDirectory = m_generatorData.buildDirectory();
    QString projectDirectory = m_generatorData.projectDirectory();

    QString srcDirectory = m_generatorData.srcDirectory();
    QString dataDirectory = m_generatorData.m5DataDirectory();
    QString debianDirectory = m_generatorData.m5DebianDirectory();

    QString widgetDirectory = m_generatorData.widgetDirectory();

    QDir dir;
    // Check the base directory, create if missing
    if (!dir.exists(basePath) && !dir.mkdir(basePath))
    {
        return false;
    }

    // Check the build directory, create if missing
    if (!dir.exists(buildDirectory) && !dir.mkdir(buildDirectory))
    {
        return false;
    }

    // Check the project directory, create if missing
    if (!dir.exists(projectDirectory) && !dir.mkdir(projectDirectory))
    {
        return false;
    }

    // check the data (icons, etc) directory
    if (!dir.exists(dataDirectory) && !dir.mkdir(dataDirectory))
    {
        return false;
    }

    if (!dir.exists(debianDirectory) && !dir.mkdir(debianDirectory))
    {
        return false;
    }

    // check the src (source for Qt app) directory, create if missing
    if (!dir.exists(srcDirectory) && !dir.mkdir(srcDirectory))
    {
        return false;
    }

    // Check the widget directory
    if (!dir.exists(widgetDirectory))
    {
        if (!dir.mkdir(widgetDirectory))
        {
            return false;
        }
    }
    else
    {
        // Clean the project directory
        DirectoryUtilities::cleanDirectory(widgetDirectory, true, widgetDirectory);
    }

    return true;
}


void Maemo5QtProjectGenerator::unzipWidgetFile(const QString & widgetFile)
{
    QFileInfo widgetFileInfo(widgetFile);
    if (widgetFileInfo.completeSuffix() == WRT_WIDGET_FILE_EXTENSION)
            m_resolvedWidgetType = WRT_WIDGET;

    QString unzipDir = m_generatorData.widgetDirectory();

    // Run unzip normally
    qDebug() << "Unzip";
    QStringList params;
    params << widgetFile << unzipDir;
    m_currentGeneratorPhase = M5_UNZIP_WIDGET;
    m_processRunner->runApp(m_currentGeneratorPhase, params);
}


void Maemo5QtProjectGenerator::sniffWidgetType()
{
    // TODO this is verbatim the same as SymbianQtProjectGenerator - factor out?

    // find config.xml
    QString w3cConfigFileName(m_generatorData.widgetDirectory() + W3C_CONFIG_FILE);
    if (QFile::exists(w3cConfigFileName))
    {
        // analyze config.xml
        QFile w3cConfigFileIn(w3cConfigFileName);
        if (!w3cConfigFileIn.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            QString errMsg = QString(ERR_FILE_OPEN_READ_FAILED_CANNOT_CONTINUE).arg(w3cConfigFileName);
            m_outputView.printOutput(errMsg);
            m_resolvedWidgetType = UNKNOWN_WIDGET;
        }
        QTextStream streamIn(&w3cConfigFileIn);
        w3cConfigFileIn.close();

        ConfigXmlParser parser(m_outputView, m_generatorData);
        parser.parse();

        QMap<QString, QString> &configXmlData = m_generatorData.configXmlData();

        if (configXmlData.contains("widget.name:"))
        {
            m_resolvedWidgetType = W3C_WIDGET;
        }
        else if (configXmlData.contains("widget.widgetname:"))
        {
            m_resolvedWidgetType = OPERA_WIDGET;
        }
    }
}


bool Maemo5QtProjectGenerator::registerStatus(bool status)
{
    if (!status)
        m_currentGeneratorPhase = M5_ENDED_WITH_ERRORS;

    return status;
}


bool Maemo5QtProjectGenerator::copyFrameworkAndPluginSrcFiles()
{
    DirectoryUtilities dirUtil(m_outputView, m_generatorData);

    // copy the framework files
    qDebug() << QApplication::applicationDirPath() + FRAMEWORK_DIR << m_generatorData.fwDirectory();
    if (!dirUtil.copyDirectory(QApplication::applicationDirPath() + FRAMEWORK_DIR, m_generatorData.fwDirectory()))
            return false;

    // copy the template files
    qDebug() << QApplication::applicationDirPath() + TEMPLATES_DIR << m_generatorData.srcDirectory();
    bool
        rv = dirUtil.copyDirectory(QApplication::applicationDirPath() + TEMPLATES_DIR,
                                   m_generatorData.srcDirectory());

    /* TODO do it later, first version ignores mobility plugins
    // copy the pugins
    qDebug() << QApplication::applicationDirPath() + PLUGINS_DIR << m_generatorData.mwDirectory();
    return dirUtil.copyDirectory(QApplication::applicationDirPath() + PLUGINS_DIR, m_generatorData.mwDirectory());
    */

    return rv;
}


bool Maemo5QtProjectGenerator::prepareEnvironmentForNonWRTWidget()
{
    FileUtilities fileUtilities(m_outputView, m_generatorData);
    bool retval = false;

    if (m_resolvedWidgetType == OPERA_WIDGET || m_resolvedWidgetType == W3C_WIDGET)
    {
        retval = fileUtilities.configXmlToInfoPlistFile(m_resolvedWidgetType);
    }
    else if (m_resolvedWidgetType == DIRECTORY)
    {
        retval = fileUtilities.directoryToInfoPlistFile();
    }

    return retval;
}


bool Maemo5QtProjectGenerator::handleWidgetConfigFile()
{
    InfoPlistParser infoPlistParser(m_outputView, m_generatorData);
    return infoPlistParser.parse();
}


bool Maemo5QtProjectGenerator::copyHybridApiJs()
{
    QString sourceFileName(QApplication::applicationDirPath()+QString(TEMPLATES_DIR) + QString(HYBRIDAPI_JS_FILE));
    QString destinationFileName(m_generatorData.infoPlistValue(KEY_WIDGET_ROOT_DIR) + HYBRIDAPI_JS_FILE);

    QFileInfo sourceInfo(sourceFileName), destinationInfo(destinationFileName);

    if (!sourceInfo.exists())
    {
        QString errMsg = QString(ERR_FILE_NOT_FOUND).arg(HYBRIDAPI_JS_FILE);
        m_outputView.printOutput(errMsg);
        return false;
    }

    if (destinationInfo.exists())
    {
        QFile destinationFile(destinationFileName);
        destinationFile.remove();
    }

    QFile::copy(sourceFileName, destinationFileName);

    return true;
}


bool Maemo5QtProjectGenerator::copyDisableSelectionCSS()
{
    QString sourceFileName(QApplication::applicationDirPath()+QString(TEMPLATES_DIR) + QString(DISABLE_SELECTION_CSS_FILE));
    QString destinationFileName(m_generatorData.infoPlistValue(KEY_WIDGET_ROOT_DIR) + DISABLE_SELECTION_CSS_FILE);

    QFileInfo sourceInfo(sourceFileName), destinationInfo(destinationFileName);

    if (!sourceInfo.exists())
    {
        QString errMsg = QString(ERR_FILE_NOT_FOUND).arg(DISABLE_SELECTION_CSS_FILE);
        m_outputView.printOutput(errMsg);
        return false;
    }

    if (destinationInfo.exists())
    {
        QFile destinationFile(destinationFileName);
        destinationFile.remove();
    }
    m_outputView.printOutput("Copy: " + sourceFileName + ", " + destinationFileName);
    QFile::copy(sourceFileName, destinationFileName);

    return true;
}


void Maemo5QtProjectGenerator::handleWidgetDirectory()
{
    QDir widgetDir = m_generatorData.widgetDirectory();
    QDir::Filters filters = QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot;
    QStringList nameFilters;
    DirectoryUtilities dirUtil(m_outputView, m_generatorData);
    qDebug() << "DIR VERSION" << widgetDir;
    dirUtil.getFiles(widgetDir.canonicalPath(),
                     filters,
                     nameFilters,
                     widgetDir.canonicalPath().length(),
                     WIDGET_SUBDIR,
                     m_generatorData.widgetSrcFiles());
    m_outputView.printOutput(QString(MSG_WIDGET_DIRECTORY_PROCESSED_N_FILES_FOUND).arg(m_generatorData.widgetSrcFiles().count()));
}


bool Maemo5QtProjectGenerator::updateMainFile()
{
    FileUtilities fileUtilities(m_outputView, m_generatorData);
    return fileUtilities.updateMainFile();
}


bool Maemo5QtProjectGenerator::updateMainWindowFile()
{
    FileUtilities fileUtilities(m_outputView, m_generatorData);
    return fileUtilities.updateMainWindowFile();
}


void Maemo5QtProjectGenerator::parseWidgetResourceFile()
{
    FileUtilities fileUtilities(m_outputView, m_generatorData);
    fileUtilities.createWidgetResourceFile();
}


bool Maemo5QtProjectGenerator::updateFrameworkProjectFile()
{
    FileUtilities fileUtilities(m_outputView, m_generatorData);
    QString fwProjectFile = m_generatorData.fwDirectory() + FRAMEWORK_PROJECT_FILE;
    qDebug() << "Updating fw project file: " << fwProjectFile;
    return fileUtilities.updateProjectFile(fwProjectFile);
}


bool Maemo5QtProjectGenerator::copyMaemo5Files()
{
    bool
        rv = false;

    // TODO should come from defines
    const QString
        TODO_MAEMO5_DIR("/templates/maemo5/");

    qDebug() << QApplication::applicationDirPath() + TODO_MAEMO5_DIR;

    FileCopier
        fileCopier(QApplication::applicationDirPath() + TODO_MAEMO5_DIR,
                   m_generatorData.projectDirectory(),
                   &m_filenameSubstitutions,
                   &m_ignorePatterns,
                   &m_keywordSubstitutions,
                   m_outputView);

    rv = fileCopier.copy();

    if (rv)
    {
        // Remove src/hybridapp.pro file (orginally copied there
        // by the reused symbian code) - we have our own src.pro in there!
        // TODO perhaps clean up this hack
        rv = QFile::remove(m_generatorData.srcDirectory() + PROJECT_TEMPLATE_FILE);
    }

    return rv;
}


bool Maemo5QtProjectGenerator::copyCopyrightFile()
{
    bool
        rv = false;

    // TODO should come from defines
    const QString
        TODO_COPYRIGHT_FILE("/templates/copyright/%1/copyright");

    // TODO should come from settings
    QString
        copyrightFile = TODO_COPYRIGHT_FILE.arg("gpl");

    qDebug() << QApplication::applicationDirPath() + copyrightFile;

    FileCopier
        fileCopier(QApplication::applicationDirPath() + copyrightFile,
                   m_generatorData.m5DebianDirectory(),
                   NULL,
                   NULL,
                   &m_keywordSubstitutions,
                   m_outputView);

    rv = fileCopier.copy();

    return rv;
}


void Maemo5QtProjectGenerator::startBuild()
{
    QStringList params;
    m_currentGeneratorPhase = M5_DPKG_BUILDPACKAGE;
    m_processRunner->runApp(m_currentGeneratorPhase, params);
}


/* OBS
bool Maemo5QtProjectGenerator::syncUnzipWidgetFile(const QString & wgzFile,
                                                   const QString & unzipDir)
{
    QFileInfo widgetFileInfo(wgzFile);

    QStringList arguments;
    arguments  << "-xo" << wgzFile << "-d" << unzipDir;


    QProcess
        * process = new QProcess( this );
    // ? process->setReadChannelMode(QProcess::MergedChannels);
    // do we need to read output in order to prevent the process
    // from stalling?

    process->start(UNZIP_APP_NAME,
                   arguments);

    process->waitForFinished(-1);

    bool
        rv = process->exitStatus() == QProcess::NormalExit
             && (process->exitCode() == 0);

    delete process;

    return rv;
}
*/

/* OBS
bool RemoveContent(QDir tmpDir)
{
    bool
        rv = false;

    QFileInfoList
        entries = tmpDir.entryInfoList(QDir::Dirs
                                       | QDir::Files
                                       | QDir::NoDotAndDotDot);
    foreach (QFileInfo entry, entries)
    {
        if (entry.isDir())
        {
            QDir
                dirEntry(entry.absoluteFilePath());
            rv = RemoveContent(dirEntry);
            rv = rv && tmpDir.rmdir(dirEntry.dirName());
        }
        else
        {
            rv = tmpDir.remove(entry.fileName());
        }
    }

    return rv;
}


bool ClearUpDir(QDir tmpDir)
{
    bool
        rv = false;

    if (tmpDir.exists())
    {
        rv = RemoveContent(tmpDir);
    }
    else
    {
        rv = tmpDir.mkpath(tmpDir.absolutePath());
    }

    return rv;
}
*/


/* OBS
QString FindFile(const QDir    & dir,
                 const QString & fileName)
{
    QString
        rv;

    if (dir.exists(fileName))
    {
        rv = dir.absolutePath() + QDir::separator() + fileName;
    }
    else
    {
        QFileInfoList
            entries = dir.entryInfoList(QDir::Dirs
                                        | QDir::NoDotAndDotDot);
        foreach (QFileInfo entry, entries)
        {
            rv = FindFile(QDir(entry.absoluteFilePath()),
                          fileName);
            if (rv.length() > 0)
                break;
        }
    }

    return rv;
}
*/


/* OBS
void Maemo5QtProjectGenerator::sniffAppNames(const QString & widgetFilePath)
{
    m_appName = "";
    m_appDisplayName = "";

    QFileInfo
        widgetFile(widgetFilePath);

    if (widgetFile.isDir())
    {
        QDir
            widgetDir(widgetFilePath);
        m_appDisplayName = widgetDir.dirName();
        m_appName = m_appDisplayName.toLower();
        m_appName.replace(" ", "");
    }
    else
    {
        QDir
            tmpDir(QDir::tempPath() + "/hybrid");

        bool
            success =  ClearUpDir(tmpDir);

        success = syncUnzipWidgetFile(widgetFilePath,
                                      tmpDir.absolutePath());

        if (success)
        {
            QXmlQuery
                xmlQuery;

            QString
                infoPlistPath(FindFile(tmpDir, INFO_PLIST_FILE));
            QString
                    xpath = "doc('%1')/descendant::dict/key[text()='DisplayName']/following-sibling::string[1]/child::text()";
            xpath = xpath.arg(infoPlistPath);
            xmlQuery.setQuery(xpath);

            QString
                text;
            success = xmlQuery.evaluateTo(&text);
            if (success)
            {
                m_appDisplayName = text.trimmed();
                m_appName = m_appDisplayName.toLower();
                m_appName.replace(" ", "");
            }
            else
            {
                QString
                    configXmlPath(FindFile(tmpDir, W3C_CONFIG_FILE));

                xpath = "doc('%1')/widget/widgetname/child::text()";
                xpath = xpath.arg(configXmlPath);
                xmlQuery.setQuery(xpath);

                success = xmlQuery.evaluateTo(&text);
                if (success)
                {
                    m_appDisplayName = text.trimmed();
                    m_appName = m_appDisplayName.toLower();
                    m_appName.replace(" ", "");
                }
                else
                {
                    // DEFAULT CASE
                    m_appDisplayName = "Hybrid Widget";
                    m_appName = "hybrid";
                }
            }
        }
    }
}
*/

namespace
{
    QString localeIndependentDayOfWeek(int dayOfWeek)
    {
        static const char * const dayAbbreviations[] = {
            "Mon",
            "Tue",
            "Wed",
            "Thu",
            "Fri",
            "Sat",
            "Sun"
        };

        QString
            rv("Day");

        if (dayOfWeek > 0 && dayOfWeek <= (int)(sizeof(dayAbbreviations)/sizeof(char*)))
        {
            rv = dayAbbreviations[dayOfWeek - 1];
        }

        return rv;
    }


    QString localeIndependentMonth(int month)
    {
        static const char * const monthAbbreviations[] = {
          "Jan",
          "Feb",
          "Mar",
          "Apr",
          "May",
          "Jun",
          "Jul",
          "Aug",
          "Sep",
          "Oct",
          "Nov",
          "Dec"
        };

        QString
            rv("Month");

        if (month > 0 && month <= (int)(sizeof(monthAbbreviations)/sizeof(char*)))
        {
            rv = monthAbbreviations[month-1];
        }

        return rv;
    }

} // namespace


void Maemo5QtProjectGenerator::updateSubstitutions(const QString & widgetFile)
{
    // OBS sniffAppNames(widgetFile);
    QPair<QString, QString>
        appNames = FileUtilities::sniffAppNames(widgetFile);
    m_appName = appNames.first;
    m_appDisplayName = appNames.second;

    // FILENAME SUBSTITUTIONS
    m_filenameSubstitutions.clear();
    m_filenameSubstitutions[FNAMESUBST_HYBRIDAPP] = m_appName;

    // the template file "hybridapp_default.ex" needs to be changed to
    // "foo.default.ex" ("foo" being package name). The reason for '_'
    // switching to '.' is that if the template file had two '.' dots,
    // Qt's FileInfo::suffix() function would be slightly confused, and
    // it's simpler to not have two dots in the template file.
    m_filenameSubstitutions[FNAMESUBST_HYBRIDAPP "_default"]
            = m_appName + QString(".default");

    // see comment aboce for the reason of '_' switching to '.'
    // template file name in this case is "hybridapp_doc-base.EX"
    // and it should turn into "foo.doc-base.EX" ("foo" being package name)
    m_filenameSubstitutions[FNAMESUBST_HYBRIDAPP "_doc-base"]
            = m_appName + QString(".doc-base");
    m_filenameSubstitutions[FNAMESUBST_HYBRIDAPP "-doc"]
            = m_appName + QString("-doc");


    // KEYWORD SUBSTITUTIONS
    m_keywordSubstitutions.clear();
    m_keywordSubstitutions[TXTSUBST_HYBRIDAPP] = m_appName; //"@hybridapp@"
    m_keywordSubstitutions[TXTSUBST_HYBRIDAPP_UC] = m_appName.toUpper(); //"@HYBRIDAPP@"
    m_keywordSubstitutions[TXTSUBST_HYBRIDAPPNAME] = m_appDisplayName; //"@hybridappname@"
    m_keywordSubstitutions[TXTSUBST_HYBRIDBINARY] = m_appName; // @hybridbinary@"
    m_keywordSubstitutions[TXTSUBST_HYBRIDAUTHOR]
            = Settings::get(Settings::HybridAuthor).toString(); // @hybridauthor@"
    m_keywordSubstitutions[TXTSUBST_HYBRIDEMAIL]
            = Settings::get(Settings::HybridEmail).toString(); // @hybridemail@"

    // TODO proper timezone handling, like "+0300"
    QDateTime
        now = QDateTime::currentDateTime().toUTC();
    QDate
        today = now.date();
    QString
        nowStr = now.toString("%1, d %2 yyyy hh:mm:ss +0000");
    nowStr = nowStr.arg(localeIndependentDayOfWeek(today.dayOfWeek()),
                        localeIndependentMonth(today.month()));
    m_keywordSubstitutions[TXTSUBST_HYBRIDDATETIME] = nowStr; // @hybriddatetime@"

    m_keywordSubstitutions[TXTSUBST_HYBRIDSHORTDESC]
            = Settings::get(Settings::HybridShortDesc, m_appName).toString(); // @hybridshortdesc@"
    m_keywordSubstitutions[TXTSUBST_HYBRIDLONGDESC]
            = Settings::get(Settings::HybridShortDesc, m_appName).toString(); // @hybridlongdesc@"

    QString
        currentYear = now.toString("yyyy");
    m_keywordSubstitutions[TXTSUBST_HYBRIDYEAR] = currentYear; //"@hybridyear@"
}
